
class Img2ASCII {

    /**
     * 
     * @param {String} ctxStr canvas 标签的ID，必填
     * @param {Object} options 参数选项, 不是必填
     * 
     * options ：
     *  mode：int 模式，模式不同显示效果不同，有 1， 2,
     *  rate：int 显示速率，值越大，帧数越少，
     *  asciiList：Array 字符列表
     *  x：int 输出横向密度，值越小越精确，也越卡
     *  y：int 输出竖向密度，值越小越精确，也越卡
     *  isFillColor：boolean 是否输出颜色
     */
    constructor(ctxStr, options = {}){
        this.ctxDom = document.getElementById(ctxStr)
        this.ctx = document.getElementById(ctxStr).getContext("2d")
        this.mode = options.mode?options.mode:1 // 模式，模式不同显示效果不同
        this.rate = options.rate?options.rate:10 // 显示速率
        this.asciiList = options.asciiList?options.asciiList:['#', '&', '@', '%', '$', 'w', '*', '+', 'o', '?', '!', ';', '^', ',', '.', ' ']
        this.x = options.x?options.x:6
        this.y = options.y?options.y:6
        this.isFillColor = options.isFillColor?true:false

    }

    /**
     * 
     * @param {dom} video 视频标签实例
     * @param {int} width 需要输出的宽度
     * @param {int} height 需要输出的高度
     */
    start(video, width = 300, height = 150) {
        const that = this
        this.stop()
        this.ctxDom.width = width
        this.ctxDom.height = height
        this.flag = setInterval(function(){
            that.ctx.drawImage(video, 0, 0, width, height);
            let data = that.ctx.getImageData(0, 0, width, height);
            that.draw(data)   
        }, this.rate)          
        
    }

    stop() {
        clearInterval(this.flag)
    }

    draw(imgData) {

        let width = imgData.width;
        let height = imgData.height;
        let data = imgData.data;
        this.ctx.clearRect(0, 0, width, height);

        for(let h = 0; h<height; h+=this.y){
            for(let w = 0; w<width; w+=this.x){
                let rgba = (width * h + w) * 4
                let ascii = this.getAscii(data[rgba], data[rgba + 1], data[rgba + 2], data[rgba + 3])
                if(this.isFillColor) this.ctx.fillStyle = `rgba(${data[rgba]},${data[rgba + 1]},${data[rgba + 2]},${data[rgba + 3]})`
                this.ctx.fillText(ascii, w, h)
            }
        }

    }

    getAscii(r, g, b, a) {
        let gary = .299 * r + .587 * g + .114 * b;
        if(this.mode == 2) gary+=500
        let i = gary % this.asciiList.length === 0 ? parseInt(gary / this.asciiList.length) - 1 : parseInt(gary/ this.asciiList.length);
        return this.asciiList[i];
    }


}

